﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AAA.Algorithm.Data;

namespace AAA.Algorithm.Cluster
{
    public class AbstractCluster
    {
        private List<INeuron> _lstSample;
        private Dictionary<object, AbstractMapNode> _dicCluster;
        private int _iLearningCount;
        private IWeight _weight;
        private ISimilarity _similarity;
        private bool _isRemoveEmptyNode = true;

        public bool IsRemoveEmptyNode
        {
            get { return _isRemoveEmptyNode; }
            set { _isRemoveEmptyNode = value; }
        }

        public AbstractCluster()
        {
            Clear();
        }

        public ISimilarity Similarity
        {
            get { return _similarity; }
            set { _similarity = value; }
        }

        public IWeight Weight
        {
            get { return _weight; }
            set { _weight = value; }
        }

        public int LearningCount
        {
            get { return _iLearningCount; }
            set { _iLearningCount = value; }
        }

        public void Clear()
        {
            _lstSample = new List<INeuron>();
            _dicCluster = new Dictionary<object, AbstractMapNode>();
        }

        public void AddNeuron(INeuron neuron)
        {
            _lstSample.Add(neuron);
        }

        public INeuron GetNeuron(int iIndex)
        {
            try
            {
                return _lstSample[iIndex];
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "," + ex.StackTrace);
            }
            return null;
        }

/*
        public AbstractMapNode GetMapNode(object oKey)
        {
            try
            {
                return _dicCluster[oKey];
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "," + ex.StackTrace);
            }
            return null;
        }
*/
        protected virtual void PreCluster(INeuron neuron, Dictionary<object, AbstractMapNode> dicCluster)
        {
        }

        protected virtual void PostCluster(float fSimilarity, float fMaxSimilarity, object oMapNodeKey, INeuron neuron, Dictionary<object, AbstractMapNode> dicCluster)
        {
        }

        public void SetMapNode(object oKey, AbstractMapNode mapNode)
        {
            try
            {
                mapNode.Key = oKey;
                if (_dicCluster.ContainsKey(oKey))
                    _dicCluster[oKey] = mapNode;
                else
                    _dicCluster.Add(oKey, mapNode);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "," + ex.StackTrace);
            }            
        }

        public int SampleCount
        {
            get { return _lstSample.Count; }
        }

        public List<object> GetClusterName()
        {
            List<object> lstClusterName = new List<object>();

            foreach (object oKey in _dicCluster.Keys)
                lstClusterName.Add(oKey);

            return lstClusterName;
        }

        public AbstractMapNode GetCluster(object oClusterName)
        {
            return _dicCluster.ContainsKey(oClusterName)
                    ?   _dicCluster[oClusterName]
                    :   null;
        }

        public void Clustering()
        {
            float fSimilarity = 0;
            float fMaxSimilarity;
            object oMapNodeKey;

            for(int i = 0; i < LearningCount; i++)
            {
                foreach (INeuron neuron in _lstSample)
                {
                    fMaxSimilarity = -float.MaxValue;
                    oMapNodeKey = null;

                    PreCluster(neuron, _dicCluster);
                    foreach (object oKey in _dicCluster.Keys)
                    {
                        _dicCluster[oKey].CurrentIteration = i;
                        fSimilarity = _dicCluster[oKey].CalculateSimilarity(neuron);
                        if (fSimilarity > fMaxSimilarity)
                        {
                            fMaxSimilarity = fSimilarity;
                            oMapNodeKey = oKey;
                        }
                    }

                    if (neuron.Cluster != null)
                    {
                        _dicCluster[neuron.Cluster].RemoveSample(neuron);

                        if ((_dicCluster[neuron.Cluster].SampleCount == 0) && IsRemoveEmptyNode)
                            _dicCluster.Remove(neuron.Cluster);
                    }

                    _dicCluster[oMapNodeKey].AddSample(neuron);

                    PostCluster(fSimilarity, fMaxSimilarity, oMapNodeKey, neuron, _dicCluster);
                }
            }
        }
    }
}
